package com.lecyon.farm.service.impl;

import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.CannedAccessControlList;
import com.aliyun.oss.model.CreateBucketRequest;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.lecyon.farm.base.BaseResponse;
import com.lecyon.farm.common.constant.CommonConstant;
import com.lecyon.farm.common.constant.FarmSysConstant;
import com.lecyon.farm.common.exception.FarmException;
import com.lecyon.farm.entity.FmAlreadySyncRecords;
import com.lecyon.farm.entity.FmSyncCar;
import com.lecyon.farm.entity.InvalidImageInformation;
import com.lecyon.farm.entity.elasticsearch.GpsPictureInformation;
import com.lecyon.farm.mapper.FmSyncCarMapper;
import com.lecyon.farm.service.*;
import com.lecyon.farm.util.StringHelper;
import com.lecyon.farm.util.ValidateUtils;
import com.lecyon.farm.vo.query.QueryFmPictureVo;
import com.lecyon.farm.vo.query.QueryGpsPictureInformationVo;
import com.lecyon.farm.vo.sync.SyncPhotoInfo;
import com.lecyon.farm.vo.view.FmPictureInfo;
import com.lecyon.farm.vo.view.ObjectStoresConfigVo;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import java.net.URL;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

/**
 * 农机基本信息表 服务实现类
 *
 * @author YaoZheng
 * @since 2020-04-13
 */
@Service
@Validated
public class FmPictureServiceImpl extends ServiceImpl<FmSyncCarMapper, FmSyncCar> implements IFmPictureService {

    private static final Logger LOG = LoggerFactory.getLogger(FmPictureServiceImpl.class);

    private IObjectStoresConfigService objectStoresConfigService;

    private ObjectStoresConfigVo objectStoresConfigVo;

    private IGpsPictureInformationService gpsPictureInformationService;

    private IFmAlreadySyncRecordsService fmAlreadySyncRecordsService;

    private ISyncMessageService syncMessageService;

    /**
     * 图片处理样式
     */
    private String PICTURE_STYLE = FarmSysConstant.ALI_OSS_PICTURE_STYLE;

    private LocalDate expirationLocalDate = LocalDate.now().plusYears(1);

    @Autowired
    public FmPictureServiceImpl(IObjectStoresConfigService objectStoresConfigService) {
        this.objectStoresConfigService = objectStoresConfigService;
        objectStoresConfigVo = this.objectStoresConfigService.getDefault();
    }

    /**
     * 根据主机号以及开始时间 结束时间 查询主机作业图片列表
     *
     * @param carId
     * @param beginTime
     * @param endTime
     * @return
     */
    @Override
    public List<FmPictureInfo> getPictureListByCarIdAndWorkDate(String carId, String beginTime, String endTime) {
        List<FmPictureInfo> result = Lists.newArrayList();
        String endpoint = objectStoresConfigVo.getEndPoint();
        String accessKeyId = objectStoresConfigVo.getAccessKeyId();
        String accessKeySecret = objectStoresConfigVo.getAccessKeySecret();
        String bucketName = objectStoresConfigVo.getBucketName();
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(CommonConstant.DATE_TIME_FORMAT_PATTERN);
        LocalDateTime beginDateTime = null;
        LocalDateTime endDateTime = null;
        if (StringUtils.isNotEmpty(beginTime)) {
            beginDateTime = LocalDateTime.parse(beginTime, dateTimeFormatter);
        }
        if (StringUtils.isNotEmpty(endTime)) {
            endDateTime = LocalDateTime.parse(endTime, dateTimeFormatter);
        }
        //如果开始时间与结束时间同时存在，则需要进行时间的逻辑判断
        if (ValidateUtils.isNotNullOrEmpty(beginDateTime) && ValidateUtils.isNotNullOrEmpty(endDateTime)) {
            if (beginDateTime.isAfter(endDateTime)) {
                LOG.error("开始时间不能晚于结束时间。beginTime : {},endTime : {}", beginTime, endTime);
                return result;
            }
        }
        if (!ossClient.doesBucketExist(bucketName)) {
            LOG.info("Creating bucket :{}", bucketName);
            ossClient.createBucket(bucketName);
            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
            createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
            ossClient.createBucket(createBucketRequest);
        }
        return null;
    }

    /**
     * 通过主机号查询图片并生成完整全路径图片URL
     *
     * @param queryFmPictureVo 查询条件
     * @return
     */
    @Override
    public List<SyncPhotoInfo> getPictureInfoList(QueryFmPictureVo queryFmPictureVo) {
        List<SyncPhotoInfo> result = Lists.newLinkedList();
        List<FmAlreadySyncRecords> fmAlreadySyncRecordsList = Lists.newLinkedList();
        String sourceTableName = "fm_repeat_work";
        String sourceMethodName = "syncPushPhoto";
        String carId = queryFmPictureVo.getCarId();
        if (StringHelper.isEmpty(carId)) {
            return result;
        }
        QueryGpsPictureInformationVo queryGpsPictureInformationVo = new QueryGpsPictureInformationVo();
        queryGpsPictureInformationVo.setCarId(queryFmPictureVo.getCarId());
        queryGpsPictureInformationVo.setBeginTime(queryFmPictureVo.getBeginTime());
        queryGpsPictureInformationVo.setEndTime(queryFmPictureVo.getEndTime());
        List<GpsPictureInformation> gpsPictureInformationList = gpsPictureInformationService.getList(queryGpsPictureInformationVo);
        if (CollectionUtils.isNotEmpty(gpsPictureInformationList)) {
            OSSClient ossClient = getOSSClient();
            if (ValidateUtils.isNotNullOrEmpty(ossClient)) {
                Instant instant = expirationLocalDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
                Date expiration = Date.from(instant);
                GeneratePresignedUrlRequest urlRequest;
                URL signedUrl;
                // 区分前后图的依据
                String frontPictureIndex1 = "_GWA80";
                String frontPictureIndex2 = "_GWA40";
                boolean frontPictureFlag;
                String picUrl;
                for (GpsPictureInformation gpsPictureInformation : gpsPictureInformationList) {
                    if (StringHelper.isEmpty(gpsPictureInformation.getPicUrl())) {
                        continue;
                    }
                    picUrl = gpsPictureInformation.getPicUrl();
                    if (picUrl.contains(frontPictureIndex1) || picUrl.contains(frontPictureIndex2)) {
                        frontPictureFlag = true;
                    } else {
                        frontPictureFlag = false;
                    }
                    urlRequest = new GeneratePresignedUrlRequest(objectStoresConfigVo.getBucketName(), picUrl, HttpMethod.GET);
                    urlRequest.setExpiration(expiration);
                    urlRequest.setProcess(PICTURE_STYLE);
                    signedUrl = ossClient.generatePresignedUrl(urlRequest);
                    if (ValidateUtils.isNullOrEmpty(signedUrl)) {
                        continue;
                    }
                    // 判断signedUrl是否有效
                    if (!StringHelper.isImagesTrue(signedUrl.toString())) {
                        // 如果url无效，则不放入集合，且在mongoDB中记录该无效图片信息
                        InvalidImageInformation invalidImageInformation = new InvalidImageInformation();
                        BeanUtils.copyProperties(gpsPictureInformation, invalidImageInformation);
                        invalidImageInformation.setId(null);
                        syncMessageService.saveInvalidImageInformation(invalidImageInformation);
                        continue;
                    }
                    SyncPhotoInfo syncPhotoInfo = new SyncPhotoInfo();
                    syncPhotoInfo.setDeviceId(carId);
                    syncPhotoInfo.setF1(Double.parseDouble(gpsPictureInformation.getGpsLon()));
                    syncPhotoInfo.setF2(Double.parseDouble(gpsPictureInformation.getGpsLat()));
                    syncPhotoInfo.setF3(gpsPictureInformation.getTime());
                    syncPhotoInfo.setF4(signedUrl.toString());
                    if (frontPictureFlag) {
                        syncPhotoInfo.setF5("1");
                    } else {
                        syncPhotoInfo.setF5("0");
                    }
                    result.add(syncPhotoInfo);
                    FmAlreadySyncRecords fmAlreadySyncRecords = new FmAlreadySyncRecords();
                    fmAlreadySyncRecords.setSourceTableName(sourceTableName);
                    fmAlreadySyncRecords.setMethodName(sourceMethodName);
                    fmAlreadySyncRecords.setSourceId(gpsPictureInformation.getId());
                    fmAlreadySyncRecordsList.add(fmAlreadySyncRecords);
                }
                if (CollectionUtils.isNotEmpty(fmAlreadySyncRecordsList)) {
                    BaseResponse recordSyncInfoResult = fmAlreadySyncRecordsService.recordSyncInfo(fmAlreadySyncRecordsList, sourceTableName, sourceMethodName);
                    if (!recordSyncInfoResult.isSuccess()) {
                        throw new FarmException(recordSyncInfoResult.getCode(), recordSyncInfoResult.getErrorMessage());
                    }
                }
            }
        }
        return result;
    }

    /**
     * 获取OSSClient
     *
     * @return OSSClient
     */
    private OSSClient getOSSClient() {
        OSSClient result;
        String endpoint = objectStoresConfigVo.getEndPoint();
        String accessKeyId = objectStoresConfigVo.getAccessKeyId();
        String accessKeySecret = objectStoresConfigVo.getAccessKeySecret();
        String bucketName = objectStoresConfigVo.getBucketName();
        result = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        if (!result.doesBucketExist(bucketName)) {
            LOG.info("Creating bucket :{}", bucketName);
            result.createBucket(bucketName);
            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
            createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
            result.createBucket(createBucketRequest);
        }
        return result;
    }


    /**
     * ----------------------------- 分割线 以下是setter方法，用于替换field上的@Autowired -----------------------------
     **/

    @Autowired
    @Lazy
    public void setGpsPictureInformationService(IGpsPictureInformationService gpsPictureInformationService) {
        this.gpsPictureInformationService = gpsPictureInformationService;
    }

    @Autowired
    @Lazy
    public void setFmAlreadySyncRecordsService(IFmAlreadySyncRecordsService fmAlreadySyncRecordsService) {
        this.fmAlreadySyncRecordsService = fmAlreadySyncRecordsService;
    }

    @Autowired
    @Lazy
    public void setSyncMessageService(ISyncMessageService syncMessageService) {
        this.syncMessageService = syncMessageService;
    }
}